
// === uuMeta ===
// depend: none
/*
window.UUMETA_DEBUG = 0;
window.UUMETA_IMAGE_DIR = "."
window.boot - user defined boot loader
String.prototype.trim(" trim white space ") - return "trim white space"
uuMeta.ua.ie - IE
uuMeta.ua.ie6 - IE6
uuMeta.ua.ie7 - IE7
uuMeta.ua.ie67 - IE6 or IE7
uuMeta.ua.iemode8 - IE8 mode 8
uuMeta.ua.quirks - Quirks mode
uuMeta.ua.opera - Opera
uuMeta.ua.gecko - Gecko
uuMeta.ua.firefox - Firefox
uuMeta.ua.webkit - WebKit
uuMeta.ua.safari - Safari, iPod, iPhone
uuMeta.ua.chrome - Google Chrome
uuMeta.ua.iphone - iPhone
uuMeta.ua.uaver - User Agent version
uuMeta.ua.rever - Rendering Engine version
uuMeta.ua.slver - Silverlight version(0, 1, 2, 3)
uuMeta.ua.flver - Flash version(0, 7, 8, 9, 10)
uuMeta.ua.canvas - Support <canvas> element
uuMeta.imagedir - image dir
uuMeta.debug - debug mode
uuMeta.dec2 - number to dec numbered hash. uuMeta.dec2[9]  -> "09"
uuMeta.hex2 - number to hex numbered hash. uuMeta.hex2[15] -> "0f"
uuMeta.root - document root, documentElement or <html>
uuMeta.html - <html>
uuMeta.head - <head>
uuMeta.mix(base, flavor, aroma = void 0, override = true) - return base
uuMeta.toArray(fake) - return array
uuMeta.boot(callback, highPriority = false)
uuMeta.blackout - black out
 */
(function uuMetaScope() {
var _mm, // inner namespace
    _win = window,
    _doc = document,
    _debug = _win.UUMETA_DEBUG || 0,
    _float = parseFloat,
    _nu = navigator.userAgent,
    _ie = !!_doc.uniqueID,
    _opera = !!_win.opera,
    _gecko = _nu.indexOf("Gecko/") > 0,
    _webkit = _nu.indexOf("WebKit") > 0,
    _chrome = _nu.indexOf("Chrome") > 0,
    _uaver = detectUserAgentVersion(),
    _rever = detectRenderingEngineVersion(),
    _ie6 = _ie && (_uaver === 6),
    _ie7 = _ie && (_uaver === 7),
    _html = _doc.getElementsByTagName("html")[0],
    _head = _doc.getElementsByTagName("head")[0],
    _boot = [0, [], []], // [fired, [high order], [low order]]
    _uid2node = {}, // { uid: node, ... }
    _TRIM = /^\s+|\s+$/g;

// inner - detect User Agent version
function detectUserAgentVersion() {
  return _opera ? (opera.version().replace(/\d$/, "") - 0) // Opera10 shock
                : _float((/(?:IE |fox\/|ome\/|ion\/)(\d+\.\d)/.
                         exec(_nu) || [,0])[1]);
}

// inner - detect Silverlight version
function detectSilverlightVersion() {
  try {
    var a = ["1.0", "2.0", "3.0"], i = 3, ok,
        o = _ie ? new ActiveXObject("AgControl.AgControl")
                : navigator.plugins["Silverlight Plug-In"];
    while (i--) {
      ok = _ie ? o.IsVersionSupported(a[i])
               : _float(/\d+\.\d+/.exec(o.description)[0]) >= _float(a[i]);
      if (ok) {
        return _float(a[i]);
      }
    }
  } catch(err) {}
  return 0;
}

// inner - detect Flash version (version 7.0 later)
function detectFlashVersion() {
  try {
    var o = _ie ? new ActiveXObject("ShockwaveFlash.ShockwaveFlash")
                : navigator.plugins["Shockwave Flash"],
        v = _ie ? o.GetVariable("$version").replace(/,/g, ".")
                : o.description,
        m = /\d+\.\d+/.exec(v);
    return m ? _float(m[0], 10) : 0;
  } catch(err) {}
  return 0;
}

// inner - detect Rendering Engine version
function detectRenderingEngineVersion() {
  return _float(((/(?:rv\:|ari\/|sto\/)(\d+\.\d+(\.\d+)?)/.
                  exec(_nu) || [,0])[1]).
                  toString().replace(/[^\d\.]/g, "").
                  replace(/^(\d+\.\d+)(\.(\d+))?$/, "$1$3"));
}

// inner - make numbering
function numbering(str) {
  var r = [], ri = -1, i = 0, j = 0,
      ary = str.split(""), az = ary.length;

  for (; i < az; ++i) {
    for (j = 0; j < az; ++j) {
      r[++ri] = ary[i] + ary[j];
    }
  }
  return r;
}

// inner - windowReadyState and domReadyState
function initDomReadyState() {
  function fire() {
    if (!_mm.blackout) {
      if (!_boot[0]++) { // [0]fired
        var ary = _boot[1].concat(_boot[2]); // copy

        if (_debug) {
          stepby(ary);
        } else {
          try {
            stepby(ary);
          } catch(err) {}
        }
        _boot = [1, [], []]; // reset
      }
    }
  }
  // callback user-function and boot loader
  function stepby(ary) {
    var v, i = 0;

    while ( (v = ary[i++]) ) { v(); }
    (typeof _win.boot === "function") && _win.boot();
  }

  if (_ie) {
    _win.attachEvent("onload", fire);
    (function peek() {
      try {
        _doc.firstChild.doScroll("up"), fire();
      } catch(err) { setTimeout(peek, 16); }
    })();
  } else { // WebKit, Firefox, Opera
    _win.addEventListener("load", fire, false);
    _doc.addEventListener("DOMContentLoaded", fire, false);
  }
}

// uuMeta.mix - mixin
function mix(base,       // @param Hash: mixin base
             flavor,     // @param Hash: add flavor
             aroma,      // @param Hash(= undefined): add aroma
             override) { // @param Boolean(= true): true is override
                         // @return Hash: base
  var i, ride = (override === void 0) || override;

  if (ride) {
    for (i in flavor) {
      base[i] = flavor[i];
    }
  } else {
    for (i in flavor) {
      !(i in base) && (base[i] = flavor[i]);
    }
  }
  return aroma ? _mm.mix(base, aroma, void 0, ride) : base;
}

// uuMeta.toArray - convert fake array to array
function toArray(fake) { // @param NodeList/Array:
                         // @return Array:
  if (!_ie && (_opera && _uaver >= 9.5)) {
    return Array.prototype.slice.call(fake, 0);
  }
  var rv = [], ri = -1, i = 0, iz = fake.length;

  for (; i < iz; ++i) {
    rv[++ri] = fake[i];
  }
  return rv;
}

// uuMeta.uid - get unique id by node
function uid(node) { // @param Node:
                     // @return Number: unique id, from 1
  var rv = node.uuqid;

  if (!rv) {
    rv = node.uuqid = ++_mm.uuqid;
    _uid2node[rv] = node;
  }
  return rv;
}

// uuMeta.uid2node - get node by unique id
function uid2node(uid) { // @param String: unique id
                         // @return Node/undefined:
  return _uid2node[uid];
}

// uuMeta.uid2node.refHash
function refHash() { // @return Hash:
  return _uid2node;
}

// inner - prebuild unique id ( node.uuqid )
function builduid() {
  var nodes = document.getElementsByTagName("*"), v, i = 0,
      id = _mm.uuqid, ie = _ie; // alias

  while ( (v = nodes[i++]) ) {
    if (!ie || v.nodeType === 1) { // 1: ELEMENT_NODE
      if (!("uuqid" in v)) {
        _uid2node[v.uuqid = ++id] = v;
      }
    }
  }
  _mm.uuqid = id; // overwrite
}

// uuMeta.boot - catch DOMContentReady/window.onload event
function boot(callback,       // @param Function:
              highPriority) { // @param Boolean(= false):
  if (callback) {
    (!_mm.blackout && _boot[0]) // [0]fired
        ? callback()
        : _boot[highPriority ? 1 : 2].push(callback); // stock
  }
}

// String.prototype.trim - trim both side whitespace
function StringTrim(str) { // @param String: " space "
                           // @return String: "space"
  return this.replace(_TRIM, "");
}

// --- initialize ---
_mm = {
  ua: {
    ie:       _ie,
    ie6:      _ie6,
    ie7:      _ie7,
    ie67:     _ie6 || _ie7,
    iemode8:  _ie && (_doc.documentMode || 0) >= 8,
    quirks:   (_doc.compatMode || "") !== "CSS1Compat",
    opera:    _opera,
    gecko:    _gecko,
    firefox:  _nu.indexOf("Firefox/") > 0,
    webkit:   _webkit,
    chrome:   _chrome,
    safari:   !_chrome && _nu.indexOf("Safari") > 0,
    iphone:   _webkit && /iPod|iPhone/.test(_nu),
    uaver:    _uaver,
    rever:    _rever,
    slver:    detectSilverlightVersion(),
    flver:    detectFlashVersion(),
    canvas:   (_ie     && _uaver >= 6)    ||
              (_opera  && _uaver >= 9.5)  ||
              (_gecko  && _rever >= 1.81) ||
              (_webkit && _rever >= 522)
  },
  debug:      _debug,
  root:       _doc.documentElement || _html,
  html:       _html,
  head:       _head,
  imagedir:   (_win.UUMETA_IMAGE_DIR || ".").replace(/\/+$/, ""),
  dec2:       numbering("0123456789"),
  hex2:       numbering("0123456789abcdef"),
  mix:        mix,
  toArray:    toArray,
  uuqid:      0,
  uid:        uid,
  uid2node:   uid2node,
  boot:       boot,
  blackout:   0, // 1: fire location.reload()
  event:      {}
};
uid2node.refHash = refHash;

initDomReadyState();
_mm.boot(builduid, 1);

// window.getComputedStyle bond. for old WebKit
if (!_ie && !_win.getComputedStyle && _doc.defaultView.getComputedStyle) {
  _win.getComputedStyle = _doc.defaultView.getComputedStyle;
}

// --- export ---
mix(String.prototype, {
  trim: StringTrim // ECMAScript-262 5th
}, 0, 0);


// versions: http://d.hatena.ne.jp/uupaa/20090603
// +------------+-------+---------+
// |            | uaver | rever   |
// +------------+-------+---------+
// | IE6        | 6.0   | 6       |
// | IE7        | 7.0   | 7       |
// | IE8(!mode8)| 7.0   | 7       |
// | IE8(mode8) | 8.0   | 8       |
// | Firefox2.0 | 2.0   | 1.81    |
// | Firefox3.0 | 3.0   | 1.9     |
// | Firefox3.5 | 3.1   | 1.91    |
// | Chrome1.0  | 1.0   | 525.19  |
// | Chrome4.0  | 4.0   | 532.0   |
// | Safar3.1   | 3.1   | 525.21  |
// | Safar4.0   | 4.0   | 530.17  |
// | Opera9.2   | 9.27  | 0       |
// | Opera9.52  | 9.52  | 0       |
// | Opera9.61  | 9.61  | 2.11 (*)| * presto version
// | Opera10.0  | 10.00 | 2.2  (*)|
// +------------+-------+---------+
_win.uuMeta = _mm; // window.uuMeta

})(); // uuMeta scope

